package com.xyhy.core.web.http;

import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.servlet.JakartaServletUtil;
import cn.hutool.extra.servlet.ServletUtil;
import lombok.Getter;

import jakarta.servlet.ReadListener;
import jakarta.servlet.ServletInputStream;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletRequestWrapper;

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.*;

/**
 * @author robert
 * @implNote 解决 filter 中读取完 body 后导致流关闭的问题；java.io.IOException Stream closed
 * @since 2025-02-26
 */
public class RequestWrapper extends HttpServletRequestWrapper {
  @Getter
  private final byte[] body;
  private final Map<String, String> headerMap;

  public RequestWrapper(HttpServletRequest request) throws IOException {
    super(request);
    if (!JakartaServletUtil.isGetMethod(request) && !JakartaServletUtil.isMultipart(request)) {
      body = read(request.getInputStream()).getBytes(StandardCharsets.UTF_8);
    } else {
      body = null;
    }

    headerMap = new HashMap<>();
  }

  public void addHeader(String key, String value) {
    headerMap.put(key, value);
  }

  @Override
  public String getHeader(String key) {
    String value = super.getHeader(key);
    if (value == null) {
      value = headerMap.get(key);
    }
    return value;
  }

  @Override
  public Enumeration<String> getHeaders(String key) {
    Enumeration<String> enumeration = super.getHeaders(key);
    List<String> valueList = Collections.list(enumeration);
    if (headerMap.containsKey(key)) {
      valueList.add(headerMap.get(key));
    }
    return Collections.enumeration(valueList);
  }

  @Override
  public Enumeration<String> getHeaderNames() {
    List<String> keyList = Collections.list(super.getHeaderNames());
    keyList.addAll(headerMap.keySet());
    return Collections.enumeration(keyList);
  }

  @Override
  public BufferedReader getReader() throws IOException {
    return new BufferedReader(new InputStreamReader(getInputStream()));

  }

  @Override
  public ServletInputStream getInputStream() throws IOException {
    ByteArrayInputStream bis = new ByteArrayInputStream(body);
    return new ServletInputStream() {
      @Override
      public boolean isFinished() {
        return false;
      }

      @Override
      public boolean isReady() {
        return false;
      }

      @Override
      public void setReadListener(ReadListener readListener) {

      }

      @Override
      public int read() throws IOException {
        return bis.read();
      }
    };
  }

  public String getBodyStr() {
    return StrUtil.str(body, StandardCharsets.UTF_8);
  }

  /**
   * 读取输入流中的参数，转化为字符串
   *
   * @param is
   * @return
   */
  private String read(InputStream is) {
    StringBuilder sb = new StringBuilder();
    BufferedReader reader = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8));
    try {
      String line;
      while ((line = reader.readLine()) != null) {
        sb.append(line);
      }
    } catch (Exception e) {
      e.printStackTrace();
    } finally {
      if (null != reader) {
        try {
          reader.close();
        } catch (IOException e) {
          e.printStackTrace();
        }
      }
    }
    return sb.toString();
  }
}
